﻿/**
 *	\file		test_samsara.cpp
 *	\date		(2015-01-01 00:46:18)/(2015-01-01 00:46:18)
 *-----------------------------------------------------------------------------
 *	\brief
 *	\version	1.0.0.1
 *	\author		Nick Shallery	(nicknide@gmail.com)
 *	\copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/
#include	"../lxsamsara/dream.h"
#include	"../lxsamsara/recurrence.h"

#include	<lolix/imp/lolix_plugin_auto_release_lib.h>

#include	<lxtrial/lxtrial.h>
#include	<lolix/lolix_inst.h>

#if __LOLIX_TMP__DEF__CHECK_LONG_JUMP
#	include	<csetjmp>
#endif // __LOLIX_TMP__DEF__CHECK_LONG_JUMP



class test_samsara
	: public lolix::itf_Tbase<test_samsara, lxtrial::icase>
{
	LOLIX_DEFINE_ITF(test_samsara, lxtrial::icase, (0x9ee3d92e, 0x08894f31, 0xb543dbc2, 0x6ed4dcef));
	lolix::dynamic_allocator* _alc;
	lxsamsara::recurrence*	_recur;
	~test_samsara(void);
public:
	static LOLIX_RETNV regist_case(lolix::lolix_regist* lx_reg);
	LOLIX_INTERFACE_DEF(name, lolix::lx_wchar const*, (void)const);
	LOLIX_INTERFACE_DEF(test, lolix::LOLIX_RETNV, (lxut::reg_pool* reg, lxtrial::probe* prb));
private:
	LOLIX_RETNV __Check_with_dream(lxtrial::probe* probe);
#if __LOLIX_TMP__DEF__CHECK_LONG_JUMP
	LOLIX_RETNV __Check_with_longjump(lxtrial::probe* probe);
#endif // __LOLIX_TMP__DEF__CHECK_LONG_JUMP
};

lolix::LOLIX_RETNV RegistTestSamsara(lolix::lolix_regist* lx_reg)
{
	return test_samsara::regist_case(lx_reg);
}


test_samsara::~test_samsara(void)
{
	_recur->release();
	_alc->release();
	lolix::imp::plugin_auto_release_lib_release();
}


lolix::LOLIX_RETNV
test_samsara::regist_case(lolix::lolix_regist* lx_reg)
{
	lolix::dynamic_allocator* alc;
	LOLIX_RETNV rtv;
	if ( LOLIX_CHECK_ERROR(rtv = lx_reg->query_itf(&alc)) )
		return rtv;
	atexit_release(*alc);
	lolix::ref_factory* ref_fac;
	if ( LOLIX_CHECK_ERROR(rtv = lx_reg->query_itf(&ref_fac)) )
		return rtv;
	atexit_release(*ref_fac);
	lxsamsara::recurrence* recur;
	if ( LOLIX_CHECK_ERROR(rtv = lx_reg->query_itf(&recur)) )
		return rtv;
	atexit_release(*recur);
	lxtrial::case_pool* cpool;
	if ( LOLIX_CHECK_ERROR(rtv = lx_reg->query_itf(&cpool)) )
		return rtv;
	atexit_release(*cpool);
	this_type* ptr;
	if ( LOLIX_CHECK_ERROR(rtv = __Create_inst_set_alc(&ptr, alc, ref_fac)) )
		return rtv;
	(ptr->_recur = recur)->inc_ref();
	atexit_release(*ptr);
	lolix::imp::plugin_auto_release_lib_inc_ref();
	return cpool->add_case(ptr);
}


lolix::lx_wchar const*
test_samsara::name(void)const
{
	return L"test/test_samsara";
}


lolix::LOLIX_RETNV
test_samsara::test(lxut::reg_pool* regp, lxtrial::probe* probe)
{
#if __LOLIX_TMP__DEF__CHECK_LONG_JUMP
	__Check_with_longjump(probe);
#endif // __LOLIX_TMP__DEF__CHECK_LONG_JUMP
	return __Check_with_dream(probe);
}


lolix::LOLIX_RETNV
test_samsara::__Check_with_dream(lxtrial::probe* probe)
{
	volatile int flags[] = {0, 0, 0, 0, 0};
	lxsamsara::dream*  dr;
	LOLIX_RETNV rtv;
	if ( LOLIX_CHECK_ERROR(rtv = this->_recur->nap(&dr)) )
		return rtv;
	atexit_invoke(*dr, release());
	probe->output("0:flags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
	++flags[0];
	probe->output("1:flags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
	if ( rtv == lolix::LOLIX_INFO_REOPERATOR )
	{
		++flags[2];
		--flags[0];
		++flags[4];
		probe->output("2:flags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
	}
	else
	{
		++flags[1];
		++flags[4];
		probe->output("3:flags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
		dr->awaken();
	}
	++flags[3];
	--flags[4];
	probe->output("4:flags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
	for ( size_t i = 0; i != ARRAY_SIZE(flags); ++i )
		if ( flags[i] != 1 )
			return LOLIX_RETURN_ERROR(lolix::LOLIX_ERROR_INVALID_OPERATOR);

	return lolix::LOLIX_RETNV_OK;
}


#if __LOLIX_TMP__DEF__CHECK_LONG_JUMP
lolix::LOLIX_RETNV
test_samsara::__Check_with_longjump(lxtrial::probe* probe)
{
	int flags[] = {0, 0, 0, 0, 0};
	jmp_buf jb;
	int rv = setjmp(jb);
	probe->output("0:jflags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
	++flags[0];
	probe->output("1:jflags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
	if ( rv )
	{
		++flags[2];
		--flags[0];
		++flags[4];
		probe->output("2:jflags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
	}
	else
	{
		++flags[1];
		++flags[4];
		probe->output("3:jflags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
		longjmp(jb, -1);
	}
	++flags[3];
	--flags[4];
	probe->output("4:jflags[] = {%I32u, %I32u, %I32u, %I32u, %I32u}", flags[0], flags[1], flags[2], flags[3], flags[4]);
	for ( size_t i = 0; i != ARRAY_SIZE(flags); ++i )
		if ( flags[i] != 1 )
			return LOLIX_RETURN_ERROR(lolix::LOLIX_ERROR_INVALID_OPERATOR);

	return lolix::LOLIX_RETNV_OK;
}
#endif // __LOLIX_TMP__DEF__CHECK_LONG_JUMP
